package com.realtime.sys.websocket;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.*;

import com.realtime.sys.service.GetDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

/**
 * @ServerEndpoint 注解是一个类层次的注解，它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@Component  // 让spring容器扫描该类
@ServerEndpoint("/uiwebSocket")  // 端点路径
public class UiWebSocket {

    private static ApplicationContext applicationContext;

    // 静态方法用于设置 ApplicationContext（通过配置类注入）
    public static void setApplicationContext(ApplicationContext context) {
        applicationContext = context;
    }

    private GetDataService getDataService;

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    // 共享线程池（所有连接共用）
    private static final ScheduledExecutorService SHARED_SCHEDULER = Executors.newScheduledThreadPool(5);

    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户标识
    private static CopyOnWriteArraySet<UiWebSocket> webSocketSet = new CopyOnWriteArraySet<UiWebSocket>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    private ScheduledFuture<?> scheduledFuture; // 用于停止定时任务


    @OnOpen
    public void onOpen(Session session) {

        // 手动获取 Bean
        this.getDataService = applicationContext.getBean(GetDataService.class);

        this.session = session;
        webSocketSet.add(this);
        addOnlineCount();
        System.out.println("新连接加入，当前在线人数：" + getOnlineCount());

        // 启动定时任务（每秒发送一次数据）
        //ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        //scheduledFuture = scheduler.scheduleAtFixedRate(this::sendDataToClient, 0, 1, TimeUnit.SECONDS);
        // 启动定时任务（使用共享线程池）
        scheduledFuture = SHARED_SCHEDULER.scheduleAtFixedRate(
                this::sendDataToClient,
                0,
                1,
                TimeUnit.SECONDS
        );
    }

    private void sendDataToClient() {
        // 检查 session 是否有效
        if (session == null || !session.isOpen()) {
            System.out.println("客户端连接已关闭，跳过发送");
            return;
        }

        try {
            String data = getDataService.getData();
            if (data == null || data.isEmpty()) {
                System.out.println("警告：获取的数据为空，跳过发送");
                return;
            }
            session.getBasicRemote().sendText(data);
            System.out.println("已发送数据：" + data);
        } catch (IOException e) {
            System.out.println("发送数据失败，客户端可能已断开：" + e.getMessage());
            // 可选：主动关闭无效连接
            try {
                session.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    @OnClose
    public void onClose() {
        if (scheduledFuture != null) {
            scheduledFuture.cancel(true);  // 仅取消当前任务，不关闭线程池
        }
        webSocketSet.remove(this);
        subOnlineCount();
        System.out.println("连接关闭，当前在线人数：" + getOnlineCount());
        if (scheduledFuture != null) {
            scheduledFuture.cancel(true); // 停止定时任务
        }
    }

    //GetDataService getDataService = new GetDataService();

    //收到客户端消息后调用的方法
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);
        //群发消息
        for (final UiWebSocket item : webSocketSet) {
            try {
                while (true) {
                    //item.sendMessage("从Redis中查询数据：" + getDataService.getAll());
                    item.sendMessage(getDataService.getData());
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
    }

    //出错时调用
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }

    //根据自己需要添加的方法
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        UiWebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        UiWebSocket.onlineCount--;
    }
}